#include "consoleplus.h"
#include "console.h"
#include <string.h>
#include <iostream>
#include <stdio.h>
#include "log.h"
#include "keys.h"

using namespace cio;
using namespace Debug;
DebugFile df;

namespace cio {

void display(const char* str, 
              int row,
              int col,
              int fieldLen) {

  static int max_row = console.getRows();
  static int max_col = console.getCols();
  int max_len = max_col - col;
  
  // as per requirements row and col is within
  // the bounds of screen otherwise results are undefined
  // so there is no checking of row and col
  console.setPosition(row, col);

  // append_str with trailing spaces
  int len = strlen(str);
  
  int temp_len = fieldLen <= 0 ? len : fieldLen;
  temp_len = temp_len < max_len ? temp_len : max_len;
  char temp_str[temp_len+1]; 
  memset(temp_str, ' ' , sizeof(temp_str));
  strncpy(temp_str, str, len);
  temp_str[temp_len] = '\0';

  console << temp_str;
}

int edit( char* str,
          int row,
          int col,
          int fieldLength,
          int maxStrLength,
          bool* insertMode,
          int* strOffset,
          int* curPosition) {

  // display
  display(str, row, col, fieldLength);

  // mode
  bool l_insertMode = *insertMode;

  // by default offset is 0
  int l_strOffset = 0;
  int l_strlen = strlen(str);

  int l_curPosition = 0;

  // if length is beyong string length
  // set to the length of the string
  // otherwise whatever is supplied
  if(strOffset)  {
    if(*strOffset > l_strlen) 
      l_strOffset = l_strlen;
    else
      l_strOffset = *strOffset;
  }

  if(curPosition) {
    if(*curPosition > fieldLength)
      l_curPosition = fieldLength;
    else
      l_curPosition = *curPosition;
  }

  const int c_strOffset = l_strOffset;

  //
  // [leftBound , rightBound] Borell set notation
  //
  const char* leftBound = str + c_strOffset;
  const char* rightBound = str + c_strOffset + fieldLength;

  // make a content copy
  char orig[fieldLength];
  memcpy(orig, str + c_strOffset , fieldLength);

  int key;
  while(1) {
    // set cursor
    console.setPosition(row, col + l_strOffset + l_curPosition);
    // get key
    console >> key;
    if(key >= ' ' && key <= '~') {
      if(l_insertMode) {
        int strlength = strlen(str);
        int spaceRemaining = maxStrLength - strlength;
        if(spaceRemaining &&
            l_curPosition && 
            l_curPosition < fieldLength) {
          int length = strlength - (l_strOffset + l_curPosition);
          memcpy(&str[l_strOffset + l_curPosition + 1],
            &str[l_strOffset + l_curPosition], length);
          str[l_strOffset + l_curPosition] = key;
          str[strlength + 1] = '\0';
          display(str, row, col, fieldLength);
          key = RIGHT;
        }
      } else {
        str[l_strOffset + l_curPosition] = key;
        console << key;
        key = RIGHT;
      }
    }

    df << key;
    df << "\n";
    switch(key) {
      case ESCAPE:
      {
        memcpy(str + c_strOffset, orig, fieldLength); 
        display(str, row, col, fieldLength);
      }
      case ENTER :
      case TAB   :
      case UP    :
      case DOWN  :
      case PGDN  :
      case PGUP  :
//      case F(1)  :  // F(1) using as INSERT on mac
      case F(2)  : 
      case F(3)  : 
      case F(4)  : 
      case F(5)  : 
      case F(6)  : 
      case F(7)  : 
      case F(8)  : 
      case F(9)  : 
      case F(10) : 
      case F(11) : 
      case F(12) : 
      {
        if(curPosition) *curPosition = l_curPosition;
        if(strOffset) *strOffset = l_strOffset;

        return key;
      } break;
      case BACKSPACE : 
      {
        int length = fieldLength - l_curPosition;
        if(l_curPosition) {
          memcpy(&str[l_strOffset + l_curPosition - 1],
            &str[l_strOffset + l_curPosition], length);
          str[l_strOffset + fieldLength - 1] = '\0';
          display(str, row, col, fieldLength);
        }
      }
      case LEFT :
      {
        if(l_curPosition) 
          l_curPosition--;
      } break;
      case HOME : 
      {
        l_curPosition = 0;
      } break;
      case RIGHT :
      {
        if(l_curPosition < fieldLength)
          l_curPosition++;
      } break;
      case END:  
      {
        l_curPosition = fieldLength;
      } break;
      case DEL:
      {
        int length = fieldLength - (l_curPosition + 1);
        if(length) {
          memcpy(&str[l_strOffset + l_curPosition],
            &str[l_strOffset + l_curPosition + 1], length);
          str[l_strOffset + fieldLength - 1] = '\0';
          display(str, row, col, fieldLength);
        }
      } break;
      case F(1):
      case INSERT: 
      {
        l_insertMode = !l_insertMode;
      } break;
      default : {
      }
    }
  }

  // change following
  return 0;
}

} // namespace cio ends
